﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Unity.VisualScripting;
using UnityEngine;
using UnityEditor;
using Object = UnityEngine.Object;

namespace EchoFramework.Editor
{
    public class PrefabBinderEditor : EditorWindow
    {
        private GameObject prefabBinderGo;
        private PrefabBinder prefabBinder;
        private List<PrefabBinder.Item> itemList;
        private List<PrefabBinder.Item> searchMatchItemList = new List<PrefabBinder.Item>();
        private Vector2 scrollViewPos;
        private List<Component> componentList = new List<Component>();
        private string itemName;
        private string itemNameSearch;
        private string lockBtnName;
        private Object itemObj;
        private bool isLock;
        private string componentStr;
        private string selectedItemName;
        private GameObject cacheSelectGo;
        private string className;

        enum ItemOption
        {
            AddItem,
            RemoveItem,
            ClearItems,
            SearchItems
        }

        enum GeneratorCodeOption
        {
            CommonCode,
            UIViewCode,
        }

        private GUIStyle m_labelSytleYellow;
        private GUIStyle m_labelStyleNormal;


        [MenuItem("EchoFramework/PrefabBinder")]
        public static void ShowWindow()
        {
            var window = GetWindow<PrefabBinderEditor>();
            window.titleContent = new GUIContent("PrefabBinder",
                AssetPreview.GetMiniTypeThumbnail(typeof(UnityEngine.EventSystems.EventSystem)), "decent");
            window.Init();
        }

        [MenuItem("GameObject/PrefabBinder Window", priority = 0)]
        public static void PrefabBinderWindow()
        {
            if (Selection.activeGameObject.GetComponent<PrefabBinder>())
                ShowWindow();
            else
                GameLogger.LogError("no PrefabBinder on this GameObject");
        }

        void Awake()
        {
            m_labelStyleNormal = new GUIStyle(EditorStyles.miniButton);
            m_labelStyleNormal.fontSize = 12;
            m_labelStyleNormal.normal.textColor = Color.white;

            m_labelSytleYellow = new GUIStyle(EditorStyles.miniButton);
            m_labelSytleYellow.fontSize = 12;
            m_labelSytleYellow.normal.textColor = Color.yellow;
        }

        void OnEnable()
        {
            EditorApplication.update += Repaint;
        }

        void OnDisable()
        {
            EditorUtility.SetDirty(prefabBinder);
            EditorApplication.update -= Repaint;
        }

        void Init()
        {
            itemList = new List<PrefabBinder.Item>();
            componentList = new List<Component>();
            lockBtnName = "锁定item组件列表";
            componentStr = string.Empty;
            isLock = false;
            if (Selection.activeGameObject.GetComponent<PrefabBinder>())
            {
                prefabBinderGo = Selection.activeGameObject;
                className = prefabBinderGo.name;
                OnRefreshBtnClicked();
            }
        }

        void OnGUI()
        {
            float offset = 0;
            float width = 10f / 3f * Screen.width / 10f;
            BeginBox(new Rect(offset, 0, width, Screen.height));
            DrawSearchBtn();
            DrawSearchItemList();
            EndBox();
            offset += width;

            width = 10f / 3f * Screen.width / 10f;
            BeginBox(new Rect(offset, 0, width, Screen.height));
            DrawLockBtn();
            GUILayout.Space(2);
            DrawComponentList();
            EndBox();
            offset += width;

            width = 10f / 3f * Screen.width / 10f;
            BeginBox(new Rect(offset, 0, width, Screen.height));
            DrawPrefabBinderField();
            GUILayout.Space(2);
            DrawItemField(width);
            GUILayout.Space(10);
            DrawCopyField(width);
            EndBox();
        }

        private void DrawSearchBtn()
        {
            GUILayout.BeginHorizontal();
            string before = itemNameSearch;
            string after = EditorGUILayout.TextField("", before, "SearchTextField");
            if (before != after) itemNameSearch = after;

            if (GUILayout.Button("", "SearchCancelButton"))
            {
                itemNameSearch = "";
                GUIUtility.keyboardControl = 0;
            }

            ComponentOperation(prefabBinder, ItemOption.SearchItems, after);
            GUILayout.EndHorizontal();
        }

        private void DrawPrefabBinderField()
        {
            EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
            GUILayout.Label("binder");
            var oldObj = prefabBinderGo;
            prefabBinderGo = EditorGUILayout.ObjectField(prefabBinderGo, typeof(GameObject), true) as GameObject;

            EditorGUILayout.EndHorizontal();
            if (!prefabBinderGo)
            {
                EditorGUILayout.HelpBox("Select a PrefabBinder Object", MessageType.Warning);
            }
            else if (oldObj != prefabBinderGo)
            {
                prefabBinder = prefabBinderGo.GetComponent<PrefabBinder>();
            }
        }

        private void BeginBox(Rect rect)
        {
            rect.height -= 20;
            GUILayout.BeginArea(rect);
            GUILayout.Box("", GUILayout.Width(rect.width), GUILayout.Height(rect.height));
            GUILayout.EndArea();
            GUILayout.BeginArea(rect);
        }

        private void EndBox()
        {
            GUILayout.EndArea();
        }

        private void DrawSearchItemList()
        {
            if (null == prefabBinderGo || null == prefabBinder)
                searchMatchItemList.Clear();
            scrollViewPos = EditorGUILayout.BeginScrollView(scrollViewPos);
            foreach (var item in searchMatchItemList)
            {
                GUILayout.BeginHorizontal();
                item.name = EditorGUILayout.TextField(item.name);
                item.obj = EditorGUILayout.ObjectField(item.obj, typeof(GameObject), true);
                if (GUILayout.Button("-", GUILayout.Width(20)))
                {
                    itemList.Remove(item);
                    prefabBinder.items = itemList.ToArray();
                    GUILayout.EndHorizontal();
                    break;
                }

                GUILayout.EndHorizontal();
            }

            EditorGUILayout.EndScrollView();
        }

        private void DrawItemField(float width)
        {
            EditorGUILayout.BeginVertical();

            GUILayout.Label(string.IsNullOrEmpty(componentStr) ? "null" : componentStr);
            if (Selection.activeObject != null)
            {
                GameObject activeGo = Selection.activeObject as GameObject;
                if (activeGo != null && cacheSelectGo != activeGo)
                {
                    itemName = activeGo.name;
                    cacheSelectGo = activeGo;
                }
            }

            itemName = EditorGUILayout.TextField(itemName);
            if (GUILayout.Button("Add Item", GUILayout.Width(width), GUILayout.Height(50)))
            {
                ComponentOperation(prefabBinder, ItemOption.AddItem);
            }

            if (GUILayout.Button("Delete Item", GUILayout.Width(width), GUILayout.Height(30)))
            {
                if (prefabBinderGo != null)
                {
                    if (string.IsNullOrEmpty(itemName))
                        GameLogger.LogWarning("请输入要删除的项目名称");
                    else
                        ComponentOperation(prefabBinder, ItemOption.RemoveItem);
                }
            }

            if (GUILayout.Button("Refresh", GUILayout.Width(width), GUILayout.Height(30)))
            {
                OnRefreshBtnClicked();
            }

            ItemTip();
        }

        private void OnRefreshBtnClicked()
        {
            if (null != prefabBinderGo)
                prefabBinder = prefabBinderGo.GetComponent<PrefabBinder>();
            if (null == prefabBinder)
            {
                itemList.Clear();
                componentList.Clear();
            }
        }

        private void DrawLockBtn()
        {
            if (GUILayout.Button(new GUIContent(lockBtnName, lockBtnName), EditorStyles.toolbarButton))
            {
                isLock = !isLock;
                if (isLock == false)
                    lockBtnName = "锁定item组件列表";
                else
                    lockBtnName = "解锁item组件列表";
            }
        }

        private void DrawComponentList()
        {
            var go = Selection.activeObject as GameObject; //获取选中对象
            if (go && isLock == false)
            {
                Component[] components = go.GetComponents<Component>();
                componentList.Clear();
                componentList.AddRange(components);
                selectedItemName = go.name;
            }

            if (go == null)
            {
                componentList.Clear();
                selectedItemName = "无选中对象";
            }

            if (go && GUILayout.Button("GameObject",
                "GameObject" == componentStr ? m_labelSytleYellow : m_labelStyleNormal))
            {
                itemObj = go;
                componentStr = "GameObject";
            }
            
            foreach (var com in componentList)
            {
                GUILayout.Space(2);
                var comType = com.GetType().ToString();
                comType = comType.Replace("UnityEngine.UI.", "");
                comType = comType.Replace("UnityEngine.", "");
                comType = comType.Replace("EchoFramework.", "");
                if (GUILayout.Button(comType, comType == componentStr ? m_labelSytleYellow : m_labelStyleNormal))
                {
                    itemObj = com;
                    componentStr = comType;
                }

                if (comType == componentStr)
                {
                    itemObj = com;
                }
            }

            EditorGUILayout.EndVertical();
        }

        private void ComponentOperation(PrefabBinder binder, ItemOption option, string name = " ")
        {
            if (null == binder) return;
            PrefabBinder.Item item = new PrefabBinder.Item();
            switch (option)
            {
                case ItemOption.AddItem:
                    AddItem(item, binder);
                    EditorUtility.SetDirty(prefabBinder);
                    break;

                case ItemOption.RemoveItem:
                    RemoveItem(item, binder);
                    EditorUtility.SetDirty(prefabBinder);
                    break;

                case ItemOption.ClearItems:
                    ClearItem(item, binder);
                    EditorUtility.SetDirty(prefabBinder);
                    break;

                case ItemOption.SearchItems:
                    SearchItem(item, binder, name);
                    break;
            }

            binder.items = itemList.ToArray();
        }

        private void AddItem(PrefabBinder.Item item, PrefabBinder binder)
        {
            item.name = itemName;
            item.obj = itemObj;
            itemList = binder.items.ToList();
            List<string> nameList = new List<string>();
            foreach (var iL in itemList)
            {
                nameList.Add(iL.name);
            }

            if (!string.IsNullOrEmpty(itemName) && itemObj != null)
            {
                if (nameList.Contains(itemName))
                {
                    GameLogger.LogError("重复元素");
                    itemList.Add(item);
                }
                else
                    itemList.Add(item);
            }
        }

        private void RemoveItem(PrefabBinder.Item item, PrefabBinder binder)
        {
            item.name = itemName;

            itemList = binder.items.ToList();
            for (int i = 0; i < itemList.Count; i++)
            {
                if (itemList[i].name.ToLower() == item.name.ToLower())
                {
                    itemList.Remove(itemList[i]);
                    break;
                }
            }
        }

        private void ClearItem(PrefabBinder.Item item, PrefabBinder binder)
        {
            item.name = itemName;
            item.obj = itemObj;
            itemList = binder.items.ToList();

            for (int i = 0; i < itemList.Count; i++)
            {
                if (itemList[i].obj == null || string.IsNullOrEmpty(itemList[i].name))
                {
                    itemList.Remove(itemList[i]);
                }
            }
        }

        private void SearchItem(PrefabBinder.Item item, PrefabBinder binder, string name)
        {
            itemList = binder.items.ToList();
            searchMatchItemList.Clear();

            foreach (var o in itemList)
            {
                if (string.IsNullOrEmpty(name))
                {
                    searchMatchItemList.Add(o);
                }
                else
                {
                    if (o.name.ToLower().Contains(name.ToLower()))
                    {
                        searchMatchItemList.Add(o);
                    }
                    else if (null != o.obj)
                    {
                        var objName = o.obj.name;
                        if (objName.ToLower().Contains(name.ToLower()))
                        {
                            searchMatchItemList.Add(o);
                        }
                    }
                }
            }
        }

        private void DrawCopyField(float width)
        {
            GUILayout.Label("代码自动生成");
            className = EditorGUILayout.TextField(className);
            if (GUILayout.Button("Generate Common Code", GUILayout.Width(width), GUILayout.Height(30)))
            {
                GeneratorOperation(GeneratorCodeOption.CommonCode);
            }

            if (GUILayout.Button("Generate UIView Code", GUILayout.Width(width), GUILayout.Height(30)))
            {
                GeneratorOperation(GeneratorCodeOption.UIViewCode);
            }
        }

        private void GeneratorOperation(GeneratorCodeOption option)
        {
            if (prefabBinderGo == null)
                return;
            if (prefabBinderGo != null)
            {
                if (string.IsNullOrEmpty(className))
                {
                    GameLogger.LogWarning("请输入自动生成的类名");
                    return;
                }
            }

            TextAsset ta = null;
            switch (option)
            {
                case GeneratorCodeOption.CommonCode:
                    ta = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/EchoFramework/Base/CommonTemplate.txt");
                    break;
                case GeneratorCodeOption.UIViewCode:
                    ta = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/EchoFramework/Base/UIViewTemplate.txt");
                    break;
                default:
                    ta = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/EchoFramework/Base/CommonTemplate.txt");
                    break;
            }

            string content = string.Empty;
            if (ta != null)
            {
                content = ta.text;
                content = content.Replace("CLASS_NAME", className);
                StringBuilder declearVarableSb = new StringBuilder();
                StringBuilder componentInitSb = new StringBuilder();
                StringBuilder buttonFunctionSb = new StringBuilder();
                foreach (var o in itemList)
                {
                    Component com = o.obj as Component;

                    string comType = com.GetType().ToString();
                    comType = comType.Replace("UnityEngine.UI.", "");
                    comType = comType.Replace("UnityEngine.", "");
                    comType = comType.Replace("EchoFramework.", "");
                    string varableFirstLower = o.name.First().ToString().ToLower() + o.name.Substring(1);
                    string varableFirstUpper = o.name.First().ToString().ToUpper() + o.name.Substring(1);

                    declearVarableSb.AppendFormat("private {0} {1};\n    ", comType, varableFirstLower);

                    componentInitSb.AppendFormat("{0} = prefabBinder.Find(\"{1}\").GetComponent<{2}>();\n        ",
                        varableFirstLower,
                        o.name, comType);
                    if (comType.Contains("Button"))
                    {
                        if (comType == "Button")
                        {
                            componentInitSb.AppendFormat("{0}.onClick.AddListener(OnClick{1});\n        ",
                                varableFirstLower,
                                varableFirstUpper);

                            buttonFunctionSb.AppendFormat("private void OnClick{0}()\n    {{\n        \n    }}\n\n    ",
                                varableFirstUpper);
                        }
                        else if (comType == "EchoButton")
                        {
                            EchoButton echoButtonComponent = com as EchoButton;
                            if (echoButtonComponent.enableSingleClick)
                            {
                                componentInitSb.AppendFormat("{0}.onClick.AddListener(OnClick{1});\n        ",
                                    varableFirstLower,
                                    varableFirstUpper);
                                buttonFunctionSb.AppendFormat(
                                    "private void OnClick{0}()\n    {{\n        \n    }}\n\n    ",
                                    o.name);
                            }

                            if (echoButtonComponent.enableDoubleClick)
                            {
                                componentInitSb.AppendFormat(
                                    "{0}.onDoubleClick.AddListener(OnDoubleClick{1});\n        ", varableFirstLower,
                                    varableFirstUpper);
                                buttonFunctionSb.AppendFormat(
                                    "private void OnDoubleClick{0}()\n    {{\n        \n    }}\n\n    ",
                                    varableFirstUpper);
                            }

                            if (echoButtonComponent.enableLongPress)
                            {
                                componentInitSb.AppendFormat("{0}.onLongPress.AddListener(onLongPress{1});\n        ",
                                    varableFirstLower,
                                    varableFirstUpper);
                                buttonFunctionSb.AppendFormat(
                                    "private void onLongPress{0}()\n    {{\n        \n    }}\n\n    ",
                                    varableFirstUpper);
                            }
                        }
                    }
                }

                content = content.Replace("DECLARE_VARABLE",
                    declearVarableSb.ToString().Substring(0, declearVarableSb.Length - 5));
                content = content.Replace("COMPONENT_INIT",
                    componentInitSb.ToString().Substring(0, componentInitSb.Length - 9));
                content = content.Replace("BUTTON_FUNTION",
                    buttonFunctionSb.Length > 0
                        ? buttonFunctionSb.ToString().Substring(0, buttonFunctionSb.Length - 6)
                        : "");

                GUIUtility.systemCopyBuffer = content;
                EditorUtility.DisplayDialog("提示", "已复制代码到剪贴板", "确定");
            }
            else
            {
                GameLogger.LogWarning("无对应模板");
            }
        }

        private void ItemTip()
        {
            if (string.IsNullOrEmpty(itemName) || itemObj == null)
            {
                string msg = string.Empty;
                if (itemObj == null)
                {
                    msg = "请选择项目组件";
                }
                else if (string.IsNullOrEmpty(itemName))
                {
                    msg = "请输入要添加的项的名字";
                }

                EditorGUILayout.HelpBox(msg, MessageType.Warning);
                EditorGUILayout.Space();
            }
        }
    }
}